﻿/*
 * Autore: Artur Tolstenco
 */

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using RecipesManager.Data;

namespace RecipesManager.MainControls.GuestSubControls
{
    /// <summary>
    /// Interaction logic for GuestMainPane.xaml
    /// </summary>
    public partial class GuestMainPane
    {
        public bool Editing;
        IGuest _currentGuest;

        readonly ObservableCollection<PersonAndRating> persons;

        readonly ObservableCollection<TasteRating> tastes;
        readonly ListCollectionView lcvTastes;

        readonly ObservableCollection<TasteRating> ingrcatricItems;
        readonly ListCollectionView lcvIngrcatricItems;
 

        public GuestMainPane()
        {
            InitializeComponent();

            persons = new ObservableCollection<PersonAndRating>();
            tastes = new ObservableCollection<TasteRating>();

            lv_persons.ItemsSource = persons;

            lcvTastes = new ListCollectionView(tastes);
            if (lcvTastes.GroupDescriptions != null)
                lcvTastes.GroupDescriptions.Add(new PropertyGroupDescription("TypeString"));
            lv_tastes.ItemsSource = lcvTastes;


            #region initialization_cb_IngredientiCategorieRicette
            ingrcatricItems = new ObservableCollection<TasteRating>();
            lcvIngrcatricItems = new ListCollectionView(ingrcatricItems);

            if (lcvIngrcatricItems.GroupDescriptions != null)
                lcvIngrcatricItems.GroupDescriptions.Add(new PropertyGroupDescription("TypeString"));
            cb_ingrcatric.ItemsSource = lcvIngrcatricItems;
            #endregion

        }


        public string CurrentGuest
        {
            get { return _currentGuest == null ? "" : tb_nomeOspite.Text; }
            set
            {
                Mouse.OverrideCursor = Cursors.Wait;
                tb_nomeOspite.Text = value;
                MyInitialize();
                tb_nomeOspite.SelectionStart = tb_nomeOspite.Text.Length;
                tb_nomeOspite.Focus();
                Editing = true;
                Mouse.OverrideCursor = null;
            }
        }

        void MyInitialize()
        {
            bt_del_person.IsEnabled = bt_del_taste.IsEnabled = false;

            if (tb_nomeOspite.Text.Equals(""))
            {
                tb_notes.Text = "";

                persons.Clear();
                tastes.Clear();
                _currentGuest = null;

                //disabilitare il bottone statistiche!
                bt_vis_stat.IsEnabled = false;

            }
            else
            {
                _currentGuest = Manager.Guests[tb_nomeOspite.Text];

                GetAllGuestData();
                SaveCurrentGuest();
                GetAllGuestData();

                bt_vis_stat.IsEnabled = true;
            }

            Refresh_IngCatRec_Combobox();
            Refresh_Guest_Combobox();
            bt_salva.IsEnabled = IsModified();
        }

        void GetAllGuestData()
        {
            persons.Clear();
            tastes.Clear();

            tb_nomeOspite.Text = _currentGuest.Name;
            tb_notes.Text = _currentGuest.Notes;

            foreach (var gr in _currentGuest.GuestRatings)
                persons.Add(new PersonAndRating(gr));
            foreach (var gr in _currentGuest.GuestRelationships)
            {
                var curPersonRating = new PersonAndRating(gr);
                var i = persons.IndexOf(curPersonRating);
                if (i < 0)
                    persons.Add(curPersonRating);
                else
                    persons[i].Needful = true;
            }

            foreach (var ir in _currentGuest.IngredientRatings)
                tastes.Add(new TasteRating(ir));
            foreach (var cr in _currentGuest.CategoryRatings)
                tastes.Add(new TasteRating(cr));
            foreach (var rr in _currentGuest.RecipeRatings)
                tastes.Add(new TasteRating(rr));

            foreach (var ii in _currentGuest.IngredientIntolerances)
            {
                var curTasteRating = new TasteRating(ii);
                var i = tastes.IndexOf(curTasteRating);
                if (i < 0)
                    tastes.Add(curTasteRating);
                else
                    tastes[i].Intolerant = true;
            }
            foreach (var ci in _currentGuest.CategoryIntolerances)
            {
                var curTasteRating = new TasteRating(ci);
                var i = tastes.IndexOf(curTasteRating);
                if (i < 0)
                    tastes.Add(curTasteRating);
                else
                    tastes[i].Intolerant = true;
            }
        }

        void Refresh_Guest_Combobox()
        {
            Mouse.OverrideCursor = Cursors.Wait;

            cb_persone.Items.Clear();

            foreach (var g in Data.Operations.Operations.AddableGuestsForGuest(_currentGuest == null ? "" : _currentGuest.Name, persons.Select(g => g.Name)))
            {
                var curPerson = g.Name;
                if (!cb_persone.Items.Contains(curPerson))
                    cb_persone.Items.Add(curPerson);
            }

            cb_persone.SelectedItem = null;

            Mouse.OverrideCursor = null;

        }

        void Refresh_IngCatRec_Combobox()
        {
            Mouse.OverrideCursor = Cursors.Wait;

            ingrcatricItems.Clear();
            
            foreach (var ir in Data.Operations.Operations.AddableIngredientsForGuest(_currentGuest == null ? "" : _currentGuest.Name, tastes.Where(t => t.IsIngredientRating()).Select(t => t.Name)))
            {
                var curTasteRating = new TasteRating(ir);
                if (!ingrcatricItems.Contains(curTasteRating))
                    ingrcatricItems.Add(curTasteRating);
            }

            foreach (var cr in Data.Operations.Operations.AddableCategoriesForGuest(_currentGuest == null ? "" : _currentGuest.Name, tastes.Where(t => t.IsCategoryRating()).Select(t => t.Name)))
            {
                var curTasteRating = new TasteRating(cr);
                if (!ingrcatricItems.Contains(curTasteRating))
                    ingrcatricItems.Add(curTasteRating);
            }


            foreach (var rr in Data.Operations.Operations.AddableRecipesForGuest(_currentGuest == null ? "" : _currentGuest.Name, tastes.Where(t => t.IsRecipeRating()).Select(t => t.Name)))
            {
                var curTasteRating = new TasteRating(rr);
                if (!ingrcatricItems.Contains(curTasteRating))
                    ingrcatricItems.Add(curTasteRating);
            }

            cb_ingrcatric.SelectedItem = null;

            Mouse.OverrideCursor = null;
        }

        public bool IsModified()
       {
            if (_currentGuest == null)
                return true;

            if (!_currentGuest.Name.ToLower().Trim().Equals(tb_nomeOspite.Text.ToLower().Trim()) ||
                !_currentGuest.Notes.ToLower().Trim().Equals(tb_notes.Text.ToLower().Trim()))
                return true;

            var gratings = persons.ToArray(); //problema!
            var grelations = persons.Where(gr => gr.IsGuestRelation()).ToArray();

            if (gratings.Count() != _currentGuest.GuestRatings.Count ||
                grelations.Count() != _currentGuest.GuestRelationships.Count)
                return true;

            foreach (var gr in _currentGuest.GuestRatings)
            {
                var curGr = gratings.FirstOrDefault(tempGr => tempGr.Name.Equals(gr.Name));

                if (curGr == null || curGr.CurRating != gr.Rating)
                    return true;
            }

            if (!_currentGuest.GuestRelationships.Select(g => g.Name).SequenceEqual(grelations.Select(g => g.Name)))
                return true;

            var iratings = tastes.Where(r => r.IsIngredientRating()).ToArray();
            var cratings = tastes.Where(r => r.IsCategoryRating()).ToArray();
            var rratings = tastes.Where(r => r.IsRecipeRating()).ToArray();

            if (_currentGuest.IngredientRatings.Count != iratings.Count() ||
                _currentGuest.CategoryRatings.Count != cratings.Count() ||
                _currentGuest.RecipeRatings.Count != rratings.Count())
                return true;

            // check in depth su irating cratings rratings

            foreach (var ir in _currentGuest.IngredientRatings)
            {
                var currentIr = iratings.FirstOrDefault(i => i.Name.Equals(ir.Name));

                if (currentIr == null || currentIr.CurRating != ir.Rating)
                    return true;
            }

            foreach (var cr in _currentGuest.CategoryRatings)
            {
                var currentCr = cratings.FirstOrDefault(c => c.Name.Equals(cr.Name));

                if (currentCr == null || currentCr.CurRating != cr.Rating)
                    return true;
            }

            foreach (var rr in _currentGuest.RecipeRatings)
            {
                var currentRr = rratings.FirstOrDefault(r => r.Name.Equals(rr.Name));

                if (currentRr == null || currentRr.CurRating != rr.Rating)
                    return true;
            }


            //ingredient && category intolerations

            var iintolerations = iratings.Where(i => i.Intolerant).ToArray();
            var cintolerations = cratings.Where(c => c.Intolerant).ToArray();

            if (_currentGuest.IngredientIntolerances.Count != iintolerations.Count() ||
                _currentGuest.CategoryIntolerances.Count != cintolerations.Count())
                return true;

            foreach (var ii in _currentGuest.IngredientIntolerances)
            {
                if (iintolerations.FirstOrDefault(i => i.Name.Equals(ii.Name)) == null)
                    return true;
            }

            foreach (var ci in _currentGuest.CategoryIntolerances)
            {
                if (cintolerations.FirstOrDefault(c => c.Name.Equals(ci.Name)) == null)
                    return true;

            }

            return false;
        }

        public bool SaveCurrentGuest()
        {
            try
            {
                if (tb_nomeOspite.Text.Trim().Equals(""))
                {
                    MessageBox.Show("Si assicuri che il nome del ospite non sia vuoto.",
                                    (string)Application.Current.FindResource("notification_dialog_type"),
                                    MessageBoxButton.OK,
                                    MessageBoxImage.Error);
                    tb_nomeOspite.SelectAll();
                    tb_nomeOspite.Focus();
                    return false;
                }


                if (_currentGuest == null)
                    _currentGuest = Manager.Guests.Add(tb_nomeOspite.Text.Trim(), tb_notes.Text.Trim());
                else
                    _currentGuest.Update(tb_nomeOspite.Text.Trim(), tb_notes.Text.Trim());

                tb_nomeOspite.Text = _currentGuest.Name;


                //ingredient part
                var iratings = tastes.Where(t => t.IsIngredientRating()).ToList();

                foreach (var ir in _currentGuest.IngredientRatings.Where(ir => !iratings.Contains(new TasteRating(ir))))
                    _currentGuest.IngredientRatings.Remove(ir.Name);

                foreach (var irating in iratings)
                    if (!_currentGuest.IngredientRatings.Contains(irating.Name))
                        _currentGuest.IngredientRatings.Add(irating.Name, irating.CurRating);
                    else
                        _currentGuest.IngredientRatings[irating.Name].Update(irating.CurRating);

                var iintolerations = iratings.Where(t => t.Intolerant).ToList();

                foreach (var ii in _currentGuest.IngredientIntolerances.Where(ii => !iintolerations.Contains(new TasteRating(ii))))
                    _currentGuest.IngredientIntolerances.Remove(ii.Name);

                foreach (var ii in iintolerations.Where(ii => !_currentGuest.IngredientIntolerances.Contains(ii.Name)))
                    _currentGuest.IngredientIntolerances.Add(ii.Name);

                //category part
                var cratings = tastes.Where(t => t.IsCategoryRating()).ToList();

                foreach (var cr in _currentGuest.CategoryRatings.Where(cr => !cratings.Contains(new TasteRating(cr))))
                    _currentGuest.CategoryRatings.Remove(cr.Name);

                foreach (var crating in cratings)
                    if (!_currentGuest.CategoryRatings.Contains(crating.Name))
                        _currentGuest.CategoryRatings.Add(crating.Name, crating.CurRating);
                    else
                        _currentGuest.CategoryRatings[crating.Name].Update(crating.CurRating);

                var cintolerations = cratings.Where(t => t.Intolerant).ToList();

                foreach(var ci in _currentGuest.CategoryIntolerances.Where(ci => !cintolerations.Contains(new TasteRating(ci))))
                    _currentGuest.CategoryIntolerances.Remove(ci.Name);

                foreach (var ci in cintolerations.Where(ci => !_currentGuest.CategoryIntolerances.Contains(ci.Name)))
                    _currentGuest.CategoryIntolerances.Add(ci.Name);

                //recipe part
                var rratings = tastes.Where(t => t.IsRecipeRating()).ToList();
                foreach (var rr in _currentGuest.RecipeRatings.Where(rr => !rratings.Contains(new TasteRating(rr))))
                    _currentGuest.RecipeRatings.Remove(rr.Name);
                foreach (var rr in rratings)
                    if (!_currentGuest.RecipeRatings.Contains(rr.Name))
                        _currentGuest.RecipeRatings.Add(rr.Name, rr.CurRating);
                    else
                        _currentGuest.RecipeRatings[rr.Name].Update(rr.CurRating);

                //persons part
                foreach (var gr in _currentGuest.GuestRatings.Where(gr => !persons.Contains(new PersonAndRating(gr))))
                    _currentGuest.GuestRatings.Remove(gr.Name);
                foreach (var p in persons)
                    if (!_currentGuest.GuestRatings.Contains(p.Name))
                        _currentGuest.GuestRatings.Add(p.Name, p.CurRating);
                    else
                        _currentGuest.GuestRatings[p.Name].Update(p.CurRating);

                var grelationships = persons.Where(g => g.Needful).ToList();
                foreach (var gr in _currentGuest.GuestRelationships.Where(gr => !grelationships.Contains(new PersonAndRating(gr))))
                    _currentGuest.GuestRelationships.Remove(gr.Name);
                foreach (var gr in grelationships.Where(gr => !_currentGuest.GuestRelationships.Contains(gr.Name)))
                    _currentGuest.GuestRelationships.Add(gr.Name);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, (string)Application.Current.FindResource("notification_dialog_type"),
                                    MessageBoxButton.OK,
                                    MessageBoxImage.Error);
                return false;
            }

            bt_salva.IsEnabled = IsModified();
            bt_vis_stat.IsEnabled = true;

            return true;
        }

        private void Tb_TextChanged(object sender, TextChangedEventArgs e)
        {
            bt_salva.IsEnabled = IsModified();
        }

        private void Bt_Del_Click(object sender, RoutedEventArgs e)
        {
            if (bt_del_taste.Equals(sender as Button))
            {
                var selectedTaste = lv_tastes.SelectedItem as TasteRating;
                if (selectedTaste == null)
                    return;

                tastes.Remove(selectedTaste);
                Refresh_IngCatRec_Combobox();
            }
            else
            {
                var selectedPerson = lv_persons.SelectedItem as PersonAndRating;
                if (selectedPerson == null)
                    return;

                persons.Remove(selectedPerson);
                Refresh_Guest_Combobox();
            }

            bt_salva.IsEnabled = IsModified();
        }

        void OnCheckedIntolerance(object sender, RoutedEventArgs e)
        {
            bt_salva.IsEnabled = IsModified();            
        }

        void OnCheckedNeedful(object sender, RoutedEventArgs e)
        {
            bt_salva.IsEnabled = IsModified();
        }

        private void Lv_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (lv_persons.Equals(sender as DataGrid))
            {
                bt_del_person.IsEnabled = lv_persons.SelectedItem != null;
            }
            else
            {
                bt_del_taste.IsEnabled = lv_tastes.SelectedItem != null;
            }
                
        }

        private void Cb_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (cb_persone.Equals(sender as ComboBox))
            {
                bt_add_person.IsEnabled = cb_persone.SelectedItem != null;
            }
            else
            {
                bt_add_taste.IsEnabled = cb_ingrcatric.SelectedItem != null;
            }
        }

        private void Bt_Add_Click(object sender, RoutedEventArgs e)
        {
            if (bt_add_person.Equals(sender as Button))
            {
                var selectedPerson = cb_persone.SelectedItem as string;
                if (selectedPerson == null)
                    return;

                persons.Add(new PersonAndRating(selectedPerson));

                Refresh_Guest_Combobox();
            }
            else
            {
                var selectedIngCatRec = cb_ingrcatric.SelectedItem as TasteRating;
                if (selectedIngCatRec == null)
                    return;

                tastes.Add(new TasteRating(selectedIngCatRec.Name, selectedIngCatRec.Type));

                Refresh_IngCatRec_Combobox();
            }

            bt_salva.IsEnabled = IsModified();
        }

        void Lv_Cb_Selectionchanged(object sender, SelectionChangedEventArgs e)
        {
            bt_salva.IsEnabled = IsModified();
        }

        private void Bt_Vis_Stat_Click(object sender, RoutedEventArgs e)
        {
            if (_currentGuest == null || _currentGuest.RecipeStats.Count == 0)
            {
                MessageBox.Show("Non ci sono statistiche per le ricette consumate da questo ospite.", (string)Application.Current.FindResource("notification_dialog_type"), MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            
            new ViewRecipesStatsWindow(_currentGuest.RecipeStats).ShowDialog();
        }
    }



    class TasteRating
    {
        private bool _intolerant;
        public enum TasteType { Category, Ingredient, Recipe }
        public readonly TasteType Type;
        public string Name { get; set; }
        public string Preference { get; set; }

        public bool Intolerant
        {
            get
            {
                return Type != TasteType.Recipe && _intolerant;
            }
            set
            {
                if (Type == TasteType.Recipe)
                    return;
                _intolerant = value;
            }
        }


        private static readonly IList<string> _allPreferences; 
        static TasteRating()
        {
            _allPreferences = new List<string>();
            _allPreferences.Add(GetStringRating(FoodRating.VeryGood));
            _allPreferences.Add(GetStringRating(FoodRating.Good));
            _allPreferences.Add(GetStringRating(FoodRating.Neuter));
            _allPreferences.Add(GetStringRating(FoodRating.Bad));
            _allPreferences.Add(GetStringRating(FoodRating.VeryBad));

        }
        public IList<string> Preferences
        {
            get { return _allPreferences; }
        } 

        public FoodRating CurRating
        {
            get { return GetFoodRating(Preference); }
        }

        public string TypeString
        {
            get
            {
                if (Type == TasteType.Recipe)
                    return Application.Current.FindResource("RecipesSectionLabel") as string;
                if (Type == TasteType.Category)
                    return Application.Current.FindResource("CategoriesSectionLabel") as string;
                return Application.Current.FindResource("IngredientsSectionLabel") as string;
            }
        }

        private TasteRating(string name, FoodRating r = FoodRating.Neuter, bool intolerant = false)
        {
            Name = name;
            Preference = GetStringRating(r);
            Intolerant = intolerant;
        }

        public TasteRating(IRating<ICategory, FoodRating> cr) : this(cr.Name, cr.Rating)
        {
            Type = TasteType.Category;   
        }

        public TasteRating(IRating<IIngredient, FoodRating> ir) : this(ir.Name, ir.Rating)
        {
            Type = TasteType.Ingredient;
        }

        public TasteRating(IRating<IRecipe, FoodRating> rr) : this(rr.Name, rr.Rating)
        {
            Type = TasteType.Recipe;
        }

        public TasteRating(string name, TasteType type) : this(name)
        {
            Type = type;
        }

        public TasteRating(IIngredient i) : this(i.Name, TasteType.Ingredient)
        {
            Intolerant = true;
        }

        public TasteRating(ICategory c) : this(c.Name, TasteType.Category)
        {
            Intolerant = true;
        }

        public TasteRating(IRecipe r) : this(r.Name, TasteType.Recipe) {}


        public bool IsCategoryRating()
        {
            return Type == TasteType.Category;
        }

        public bool IsIngredientRating()
        {
            return Type == TasteType.Ingredient;
        }

        public bool IsRecipeRating()
        {
            return Type == TasteType.Recipe;
        }
        
        public static string GetStringRating(FoodRating? r)
        {
            switch (r)
            {
                case FoodRating.VeryGood:
                    return Application.Current.FindResource("FoodRatingVeryGood") as string;
                case FoodRating.Good:
                    return Application.Current.FindResource("FoodRatingGood") as string;
                case FoodRating.Neuter:
                    return Application.Current.FindResource("FoodRatingNeuter") as string;
                case FoodRating.Bad:
                    return Application.Current.FindResource("FoodRatingBad") as string;
                case FoodRating.VeryBad:
                    return Application.Current.FindResource("FoodRatingVeryBad") as string;
            }

            return Application.Current.FindResource("FoodRatingNeuter") as string;
        }

        static FoodRating GetFoodRating(string r)
        {
            string tmp;

            if ((tmp = (string)Application.Current.FindResource("FoodRatingVeryGood")) != null && tmp.Equals(r))
                return FoodRating.VeryGood;
            if ((tmp = (string)Application.Current.FindResource("FoodRatingGood")) != null && tmp.Equals(r))
                return FoodRating.Good;
            if ((tmp = (string)Application.Current.FindResource("FoodRatingNeuter")) != null && tmp.Equals(r))
                return FoodRating.Neuter;
            if ((tmp = (string)Application.Current.FindResource("FoodRatingBad")) != null && tmp.Equals(r))
                return FoodRating.Bad;
            return FoodRating.VeryBad;
        }

        bool Equals(TasteRating other)
        {
            return string.Equals(Name, other.Name) && Type == other.Type;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != GetType()) return false;
            return Equals((TasteRating) obj);
        }

        public override int GetHashCode()
        {
            return (Name != null ? Name.GetHashCode() : 0);
        }
    }

    public class PersonAndRating
    {
        public string Name { get; private set; }
        public string Preference { get; set; }
        public bool Needful { get; set; }
        public GuestRating CurRating {
            get { return GetGuestRating(Preference); }
        }

        private static readonly IList<string> _preferences;
        public IList<string> Preferences { get { return _preferences; } } 
        static PersonAndRating()
        {
            _preferences = new List<string>
                               {
                                   GetStringRating(GuestRating.VeryGood),
                                   GetStringRating(GuestRating.Good),
                                   GetStringRating(GuestRating.Neuter),
                                   GetStringRating(GuestRating.Bad),
                                   GetStringRating(GuestRating.VeryBad)
                               };
        }

        static string GetStringRating(GuestRating r)
        {
            switch (r)
            {
                case GuestRating.VeryGood:
                    return Application.Current.FindResource("GuestRatingVeryGood") as string;
                case GuestRating.Good:
                    return Application.Current.FindResource("GuestRatingGood") as string;
                case GuestRating.Neuter:
                    return Application.Current.FindResource("GuestRatingNeuter") as string;
                case GuestRating.Bad:
                    return Application.Current.FindResource("GuestRatingBad") as string;
                case GuestRating.VeryBad:
                    return Application.Current.FindResource("GuestRatingVeryBad") as string;
            }

            return Application.Current.FindResource("GuestRatingNeuter") as string;
        }

        static GuestRating GetGuestRating(string r)
        {
            string tmp;

            if ((tmp = (string)Application.Current.FindResource("GuestRatingVeryGood")) != null && tmp.Equals(r))
                return GuestRating.VeryGood;
            if ((tmp = (string)Application.Current.FindResource("GuestRatingGood")) != null && tmp.Equals(r))
                return GuestRating.Good;
            if ((tmp = (string)Application.Current.FindResource("GuestRatingNeuter")) != null && tmp.Equals(r))
                return GuestRating.Neuter;
            if ((tmp = (string)Application.Current.FindResource("GuestRatingBad")) != null && tmp.Equals(r))
                return GuestRating.Bad;

            return GuestRating.VeryBad;
        }


        public PersonAndRating(string name, GuestRating rating = GuestRating.Neuter, bool needful = false)
        {
            Name = name;
            Preference = GetStringRating(rating);
            Needful = needful;
        }
        public PersonAndRating(IRating<IGuest, GuestRating> gr) : this(gr.Name, gr.Rating) { }

        public PersonAndRating(IGuest g) : this(g.Name, GuestRating.Neuter, true) { }


        public bool IsGuestRelation()
        {
            return Needful;
        }


        bool Equals(PersonAndRating other)
        {
            return string.Equals(Name, other.Name);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != GetType()) return false;
            return Equals((PersonAndRating) obj);
        }

        public override int GetHashCode()
        {
            return (Name != null ? Name.GetHashCode() : 0);
        }
    }

}

